package handler

import (
	"crypto"
	_ "crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"gitcode.net/togolife/nfttoken/common"
	ipfs "github.com/ipfs/go-ipfs-api"
)

type UploadToIpfsInput struct {
	LocalUrl string `json:"localUrl"`
	Sign     string `json:"sign"`
}

type UploadToIpfsOutput struct {
	RetCode int    `json:"retCode"`
	RetMsg  string `json:"retMsg"`
	IpfsUri string `json:"ipfsUri,omitempty"`
}

func UploadToIpfsRet(w http.ResponseWriter, out *UploadToIpfsOutput) {
	v, err := json.Marshal(out)
	if err != nil {
		return
	}
	w.Write(v)
}

func setUploadToIpfsOutput(out *UploadToIpfsOutput, err common.NftError) {
	out.RetCode = err.ErrorNo
	out.RetMsg = err.ErrorMsg
}

func (input *UploadToIpfsInput) checkSign() bool {
	s := "localUrl=" + input.LocalUrl
	s += "&sign=" + hdConf.SignRandomKey
	m := crypto.SHA256.New()
	m.Write([]byte(s))
	v := hex.EncodeToString(m.Sum(nil))
	return v == input.Sign
}

func UploadToIpfsIf(w http.ResponseWriter, req *http.Request) {
	input := UploadToIpfsInput{}
	output := UploadToIpfsOutput{}
	defer UploadToIpfsRet(w, &output)
	body, err := ioutil.ReadAll(req.Body)
	if err != nil {
		hdLog.LogE("Read upload to ipfs http request body failed! [%v]", err)
		setUploadToIpfsOutput(&output, common.NewError(400))
		return
	}
	err = json.Unmarshal(body, &input)
	if err != nil {
		hdLog.LogE("Decode upload to ipfs http request body failed! [%v]", err)
		setUploadToIpfsOutput(&output, common.NewError(400))
		return
	}
	if !input.checkSign() {
		hdLog.LogE("Check input sign failed!")
		setUploadToIpfsOutput(&output, common.NewError(401))
		return
	}
	if len(hdConf.IpfsNodePath) <= 0 {
		hdLog.LogE("Not set ipfs server path!")
		setUploadToIpfsOutput(&output, common.NewError(503))
		return
	}
	v, err := http.Get(input.LocalUrl)
	if err != nil {
		hdLog.LogE("Http get [%v] failed! [%v]", input.LocalUrl, err)
		setUploadToIpfsOutput(&output, common.NewError(402))
		return
	}
	defer v.Body.Close()
	ipfsClient := ipfs.NewShell(hdConf.IpfsNodePath)
	cid, err := ipfsClient.Add(v.Body)
	if err != nil {
		hdLog.LogE("Add file to ipfs failed! [%v]", err)
		setUploadToIpfsOutput(&output, common.NewError(504))
		return
	}
	output.IpfsUri = cid
	setUploadToIpfsOutput(&output, common.NewError(200))
	return
}
